﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.IO;
using System.Text;
using Bea.Tuxedo.ATMI;

namespace XFSale.Lib
{
    using DictMetaSet = Dictionary<string, DictMeta>;
    using PackMetaSet = Dictionary<string, PackMeta>;
    using MenuMetaSet = List<MenuMeta>;

    public delegate void AppCallBack(Pack response);

    public static class App
    {
        //定义元信息文件类型
        private const int METAFILE_PACK = 1;	//数据包信息文件
        private const int METAFILE_DICT = 2; //数据字典信息文件
        private const int METAFILE_MENU = 3; //菜单项信息文件

        public const int PACKFILE_MAXSIZE = (16 * 1024); //包信息文件最大
        public const int DICTFILE_MAXSIZE = (512 * 1024); //字典取值文件最大
        public const int MENUFILE_MAXSIZE = (16 * 1024); //字典取值文件最大

        private static PackMetaSet _packMeta = null;
        private static DictMetaSet _dictMeta = null;
        private static MenuMetaSet _menuMeta = null;
        private static Pack _request = null;
        private static Pack _response = null;
        private static Global _operator = null;

        public static PackMetaSet PackMeta
        {
            get { return _packMeta; }
        }
        public static DictMetaSet DictMeta
        {
            get { return _dictMeta; }
        }
        public static MenuMetaSet MenuMeta
        {
            get { return _menuMeta; }
        }
        public static Pack Request
        {
            get { return _request; }
        }
        public static Pack Response
        {
            get { return _response; }
        }
        public static Global Global
        {
            get { return _operator; }
        }

        public static void Init()
        {
            try
            {
                Log.LogTo = Convert.ToInt32(ConfigurationManager.AppSettings["LogTo"]);
                Log.LogLevel = Convert.ToInt32(ConfigurationManager.AppSettings["LogLevel"]);
                Log.LogFile = ConfigurationManager.AppSettings["LogFile"];
                Log.LogReset = ConfigurationManager.AppSettings["LogReset"].ToUpper().Equals("Y");

            }
            catch
            {
                Log.LogTo = Log.LOGTO_FILE;
                Log.LogLevel = Log.LOGLVL_DEBUG;
                Log.LogFile = "Runtime.log";

                Log.LogThrowError("读取日志配置失败");
            }

            try
            {
                if (Log.LogReset)
                {
                    File.Delete(Log.LogFile);
                }
            }
            catch
            {
                Log.LogThrowError("删除日志文件失败");
            }

            Log.LogDebug("开始初始化客户端");

            Log.LogDebug("设置TUXEDO环境变量");
            try
            {
                Utils.tuxputenv(ConfigurationSettings.AppSettings["TuxEnv"]);
            }
            catch
            {
                Log.LogThrowError("设置TUXEDO环境变量失败");
            }

            Log.LogDebug("初始化字典信息");
            _InitDictMeta();

            //Log.LogDebug("记录字典信息日志");
            //Log.LogDictMeta();

            Log.LogDebug("初始化包信息");
            _InitPackMeta();

            //Log.LogDebug("记录包信息日志");
            //Log.LogPackMeta();

            Log.LogDebug("初始化菜单信息");
            _InitMenuMeta();

            Log.LogDebug("初始化用户信息");
            _InitOperator();

            Log.LogDebug("初始化请求和应答包");
            _InitPack();

            Log.LogDebug("结束初始化客户端");
        }
        public static void Dispose()
        {
            Log.LogDebug("开始释放客户端");

            Log.LogDebug("释放请求和应答包");
            _DisposePack();

            Log.LogDebug("释放用户信息");
            _DisposeOperator();

            Log.LogDebug("释放菜单信息");
            _DisposeMenuMeta();

            Log.LogDebug("释放数据字典取值");
            _DisposeDictMenu();

            Log.LogDebug("释放包信息");
            _DisposePackMeta();

            Log.LogDebug("结束释放客户端");
        }

        public static void CallService(string svcName)
        {
            CallService(svcName, null);
        }

        public static void CallService(string svcName, AppCallBack callBack)
        {
            TypedBuffer rqstBuff = null;
            TypedBuffer respBuff = null;

            try
            {
                Log.LogInfo("填充请求默认值");
                Request.DefRecordByAll();

                Log.LogInfo("写请求包日志");
                Log.LogRequest();

                Log.LogDebug("分配请求缓冲区");
                try
                {
                    rqstBuff = new TypedCArray(Request.PackLen);
                }
                catch
                {
                    Log.LogThrowError("分配请求缓冲区失败");
                }


                Log.LogDebug("拷贝请求数据包到请求缓冲区");
                Request.PutToBuff(rqstBuff as TypedCArray);

                Log.LogDebug("初始化应答包");
                Response.ServiceCode = Request.ServiceCode;
                Response.PackType = Pack.PACKTYPE_RESPONSE;
                Response.Init();

                Log.LogDebug("分配应答缓冲区");
                try
                {
                    respBuff = new TypedCArray(Response.PackLen);
                }
                catch
                {
                    Log.LogThrowError("分配应答缓冲区失败");
                }

                try
                {
                    Log.LogDebug("初始化TUXEDO");
                    AppContext context = AppContext.tpinit(null);

                    Log.LogDebug("开始调用服务");
                    context.tpcall(svcName, rqstBuff, ref respBuff, ATMIC.TPNOBLOCK);

                    Log.LogDebug("结束TUXEDO");
                    context.tpterm();
                }
                catch
                {
                    Log.LogThrowError("调用服务失败");
                }

                Log.LogDebug("从应答缓冲区拷贝到应答数据包");
                Response.GetFromBuff(respBuff as TypedCArray);

                Log.LogInfo("写应答包日志");
                Log.LogResponse();

                Log.LogDebug("开始调用回调函数");
                if (callBack != null)
                    callBack(Response);
            }
            catch
            {
                Log.LogThrowError("调用服务失败");
            }
            finally
            {
                Log.LogDebug("释放应答包");
                Response.Dispose();

                Log.LogDebug("释放缓冲区");
                rqstBuff = null;
                respBuff = null;
            }
        }

        private static void _InitPackMeta()
        {
            _packMeta = new PackMetaSet();
            _request = new Pack();
            _response = new Pack();

            TypedBuffer rqstBuff = null;
            TypedBuffer respBuff = null;
            Log.LogDebug("开始分配请求缓冲区");
            try
            {
                rqstBuff = new TypedCArray(2);
                (rqstBuff as TypedCArray).PutBytes(StringUtil.StrToBytes("1"));
            }
            catch
            {
                Log.LogThrowError("分配请求缓冲区失败");
            }

            Log.LogDebug("开始分配应答缓冲区");
            try
            {
                respBuff = new TypedCArray(PACKFILE_MAXSIZE);
            }
            catch (TPException ex)
            {
                Log.LogThrowError("分配应答缓冲区失败 TUX-{0} {1}", ex.TPErrno, ex.Message);
            }

            try
            {
                Log.LogDebug("初始化TUXEDO");
                AppContext context = AppContext.tpinit(null);

                Log.LogDebug("开始调用服务");
                context.tpcall("F000001", rqstBuff, ref respBuff, ATMIC.TPNOBLOCK);

                Log.LogDebug("结束TUXEDO");
                context.tpterm();
            }
            catch (TPException e)
            {
                Log.LogThrowError("获取包信息文件失败 TUX-{0}", e.TPErrno);
            }


            byte[] buff = null;
            MemoryStream ms = null;
            StreamReader sr = null;
            try
            {
                buff = new byte[respBuff.Size];
                (respBuff as TypedCArray).GetBytes(buff);
                ms = new MemoryStream(buff);
                sr = new StreamReader(ms, Encoding.Default);

                string line = string.Empty;
                byte[] bytes = null;
                int pos = 0;
                int len = 0;
                PackMeta pm = null;
                PackItem pi = null;

                Log.LogVerbose("初始化包信息");
                string key = string.Empty;
                while (!sr.EndOfStream)
                {
                    line = sr.ReadLine();

                    if (string.IsNullOrEmpty(line))
                        continue;

                    if (string.IsNullOrEmpty(line.Trim(new char[] { '\x20', '\x00' })))
                        continue;

                    pos = 2;
                    bytes = StringUtil.StrToBytes(line);

                    string type = line.Substring(0, 1);
                    if (type == "P")    //包信息
                    {
                        pm = new PackMeta();

                        len = 6 + 1;
                        pm.serviceCode = StringUtil.BytesToStr(bytes, pos, len);
                        pos += len;

                        len = 1 + 1;
                        pm.packType = StringUtil.BytesToStr(bytes, pos, len);
                        pos += len;

                        len = 1 + 1;
                        pm.recordType = StringUtil.BytesToStr(bytes, pos, len);
                        pos += len;

                        key = pm.serviceCode.ToUpper() + pm.packType.ToUpper();
                        _packMeta.Add(key, pm);
                        Log.LogDebug("加入包信息: {0}", key);
                    }
                    else if (type == "I")    //数据项信息
                    {
                        pi = new PackItem();

                        len = 4 + 1;
                        pi.itemOrder = Convert.ToInt32(StringUtil.BytesToStr(bytes, pos, len));
                        pos += len;

                        //len = 4 + 1;
                        //pi.itemID = Convert.ToInt32(StringUtil.BytesToStr(bytes, pos, len));
                        //pos += len;

                        len = 45 + 1;
                        pi.itemName = StringUtil.BytesToStr(bytes, pos, len);
                        pos += len;

                        pm.packItems.Add(pi);
                        Log.LogVerbose("加入数据项信息: {0} {1}", pi.itemOrder, pi.itemName);
                    }
                    else
                    {
                        continue;
                    }
                }
            }
            finally
            {
                buff = null;
                if (sr != null)
                {
                    sr.Close();
                }
                if (ms != null)
                {
                    ms.Close();
                }
            }
        }
        private static void _DisposePackMeta()
        {
            if (_packMeta != null)
            {
                _packMeta.Clear();
                _packMeta = null;
            }
        }

        private static void _InitDictMeta()
        {
            _dictMeta = new DictMetaSet();

            TypedBuffer rqstBuff = null;
            TypedBuffer respBuff = null;
            Log.LogDebug("开始分配请求缓冲区");
            try
            {
                rqstBuff = new TypedCArray(2);
                (rqstBuff as TypedCArray).PutBytes(StringUtil.StrToBytes("2"));
            }
            catch
            {
                Log.LogThrowError("分配请求缓冲区失败");
            }

            Log.LogDebug("开始分配应答缓冲区");
            try
            {
                respBuff = new TypedCArray(DICTFILE_MAXSIZE);
            }
            catch (TPException ex)
            {
                Log.LogThrowError("分配应答缓冲区失败 TUX-{0} {1}", ex.TPErrno, ex.Message);
            }

            try
            {
                Log.LogDebug("初始化TUXEDO");
                AppContext context = AppContext.tpinit(null);

                Log.LogDebug("开始调用服务");
                context.tpcall("F000001", rqstBuff, ref respBuff, ATMIC.TPNOBLOCK);

                Log.LogDebug("结束TUXEDO");
                context.tpterm();
            }
            catch (TPException e)
            {
                Log.LogThrowError("获取字典文件失败 TUX-{0}", e.TPErrno);
            }

            byte[] buff = null;
            MemoryStream ms = null;
            StreamReader sr = null;
            try
            {
                buff = new byte[respBuff.Size];
                (respBuff as TypedCArray).GetBytes(buff);
                ms = new MemoryStream(buff);
                sr = new StreamReader(ms, Encoding.Default);

                string line = string.Empty;
                byte[] bytes = null;
                int pos = 0;
                int len = 0;
                DictMeta dm = null;
                DictValue dv = null;

                Log.LogVerbose("初始化字典信息");
                while (!sr.EndOfStream)
                {
                    line = sr.ReadLine();

                    if (string.IsNullOrEmpty(line))
                        continue;

                    if (string.IsNullOrEmpty(line.Trim(new char[] { '\x20', '\x00' })))
                        continue;

                    pos = 2;
                    bytes = StringUtil.StrToBytes(line);

                    string type = line.Substring(0, 1);
                    if (type == "D")    //字典信息
                    {
                        dm = new DictMeta();

                        len = 4 + 1;
                        dm.itemID = Convert.ToInt32(StringUtil.BytesToStr(bytes, pos, len));
                        pos += len;

                        len = 45 + 1;
                        dm.itemName = StringUtil.BytesToStr(bytes, pos, len);
                        pos += len;

                        len = 1 + 1;
                        dm.itemType = StringUtil.BytesToStr(bytes, pos, len);
                        pos += len;

                        len = 4 + 1;
                        dm.itemScale = Convert.ToInt32(StringUtil.BytesToStr(bytes, pos, len));
                        pos += len;

                        len = 2 + 1;
                        dm.itemPrecise = Convert.ToInt32(StringUtil.BytesToStr(bytes, pos, len));
                        pos += len;

                        len = 50 + 1;
                        dm.itemDefault = StringUtil.BytesToStr(bytes, pos, len);
                        pos += len;

                        len = 30 + 1;
                        dm.itemVerify = StringUtil.BytesToStr(bytes, pos, len);
                        pos += len;

                        len = 4 + 1;
                        dm.itemDefault = StringUtil.BytesToStr(bytes, pos, len);
                        pos += len;

                        len = 30 + 1;
                        dm.fieldName = StringUtil.BytesToStr(bytes, pos, len);
                        pos += len;

                        _dictMeta.Add(dm.itemName.ToUpper(), dm);
                        Log.LogDebug("加入字典信息: {0}", dm.itemName.ToUpper());
                    }
                    else if (type == "V")    //取值信息
                    {
                        dv = new DictValue();

                        len = 4 + 1;
                        dv.itemValue = StringUtil.BytesToStr(bytes, pos, len);
                        pos += len;

                        len = 50 + 1;
                        dv.valueDesc = StringUtil.BytesToStr(bytes, pos, len);
                        pos += len;

                        dm.valueItems.Add(dv);
                        Log.LogVerbose("加入取值信息: {0} {1}", dv.itemValue, dv.valueDesc);
                    }
                    else
                    {
                        continue;
                    }
                }
            }
            finally
            {
                buff = null;
                if (sr != null)
                {
                    sr.Close();
                }
                if (ms != null)
                {
                    ms.Close();
                }
            }
        }

        private static void _DisposeDictMenu()
        {
            if (_dictMeta != null)
            {
                _dictMeta.Clear();
                _dictMeta = null;
            }
        }

        private static void _InitMenuMeta()
        {
            _menuMeta = new MenuMetaSet();

            TypedBuffer rqstBuff = null;
            TypedBuffer respBuff = null;
            Log.LogDebug("开始分配请求缓冲区");
            try
            {
                rqstBuff = new TypedCArray(2);
                (rqstBuff as TypedCArray).PutBytes(StringUtil.StrToBytes("3"));
            }
            catch
            {
                Log.LogThrowError("分配请求缓冲区失败");
            }

            Log.LogDebug("开始分配应答缓冲区");
            try
            {
                respBuff = new TypedCArray(DICTFILE_MAXSIZE);
            }
            catch (TPException ex)
            {
                Log.LogThrowError("分配应答缓冲区失败 TUX-{0} {1}", ex.TPErrno, ex.Message);
            }

            try
            {
                Log.LogDebug("初始化TUXEDO");
                AppContext context = AppContext.tpinit(null);

                Log.LogDebug("开始调用服务");
                context.tpcall("F000001", rqstBuff, ref respBuff, ATMIC.TPNOBLOCK);

                Log.LogDebug("结束TUXEDO");
                context.tpterm();
            }
            catch (TPException e)
            {
                Log.LogThrowError("获取菜单文件失败 TUX-{0}", e.TPErrno);
            }

            byte[] buff = null;
            MemoryStream ms = null;
            StreamReader sr = null;
            try
            {
                buff = new byte[respBuff.Size];
                (respBuff as TypedCArray).GetBytes(buff);
                ms = new MemoryStream(buff);
                sr = new StreamReader(ms, Encoding.Default);

                string line = string.Empty;
                byte[] bytes = null;
                int pos = 0;
                int len = 0;
                MenuMeta dm = null;

                Log.LogVerbose("初始化菜单信息");
                while (!sr.EndOfStream)
                {
                    line = sr.ReadLine();

                    if (string.IsNullOrEmpty(line))
                        continue;

                    if (string.IsNullOrEmpty(line.Trim(new char[] { '\x20', '\x00' })))
                        continue;

                    pos = 0;
                    bytes = StringUtil.StrToBytes(line);

                    dm = new MenuMeta();

                    len = 6 + 1;
                    dm.menuID = StringUtil.BytesToStr(bytes, pos, len);
                    pos += len;

                    len = 60 + 1;
                    dm.menuCaption = StringUtil.BytesToStr(bytes, pos, len);
                    pos += len;

                    len = 20 + 1;
                    dm.menuIcon = StringUtil.BytesToStr(bytes, pos, len);
                    pos += len;

                    len = 6 + 1;
                    dm.menuHotKey = StringUtil.BytesToStr(bytes, pos, len);
                    pos += len;

                    len = 6 + 1;
                    dm.menuOrder = Convert.ToInt32(StringUtil.BytesToStr(bytes, pos, len));
                    pos += len;

                    len = 20 + 1;
                    dm.callDLL = StringUtil.BytesToStr(bytes, pos, len);
                    pos += len;

                    len = 60 + 1;
                    dm.callFunc = StringUtil.BytesToStr(bytes, pos, len);
                    pos += len;

                    len = 20 + 1;
                    dm.callParam = StringUtil.BytesToStr(bytes, pos, len);
                    pos += len;

                    _menuMeta.Add(dm);
                    Log.LogDebug("加入菜单信息: {0} {1}", dm.menuID, dm.menuCaption);
                }

                line = null;
                bytes = null;
                dm = null;
            }
            finally
            {
                buff = null;
                if (sr != null)
                {
                    sr.Close();
                }
                if (ms != null)
                {
                    ms.Close();
                }
            }
        }

        private static void _DisposeMenuMeta()
        {
            if (_menuMeta != null)
            {
                _menuMeta.Clear();
                _menuMeta = null;
            }
        }

        private static void _InitPack()
        {
            _request = new Pack();
            _response = new Pack();
        }

        private static void _DisposePack()
        {
            if (_request != null)
            {
                _request.Dispose();
                _request = null;
            }
            if (_response != null)
            {
                _response.Dispose();
                _response = null;
            }
        }

        private static void _InitOperator()
        {
            _operator = new Global();
        }

        private static void _DisposeOperator()
        {
            if (_operator != null)
            {
                _operator = null;
            }
        }
    }
}
